package com.panomedic.log4j;

import com.panomedic.Constants;
import com.panomedic.kernel.Kernel;
import java.io.FileInputStream;
import java.util.List;
import java.util.ArrayList;
import java.util.StringTokenizer;
import java.util.PropertyResourceBundle;


public class Logger {

    private org.apache.log4j.Logger logger;

    private static List<String> filteredCategories;

    private static final String INTERNAL_ERROR = "INTERNAL ERROR";

    static
    {
        filteredCategories = new ArrayList<String>();
        
        try 
        {
            PropertyResourceBundle bundle = new PropertyResourceBundle(new FileInputStream(Constants.LOG_FILTERS_FILE));
            String value = bundle.getString("log.filter");
            StringTokenizer st = new StringTokenizer(value, ",");
        
            while (st.hasMoreTokens()) 
            {
                String v = st.nextToken().trim();
                filteredCategories.add(v);
            }
            
        } catch (Exception e) {
            System.out.println(Constants.LOG_FILTERS_FILE + " not found or incorrect. No filters will be applied to log");
        }
    }
    
    public Logger() {
        // Get invoker class and call Log4j getLogger
        Throwable t = new Throwable();
        StackTraceElement[] s = t.getStackTrace();
        String className = s[1].getClassName();
        Class cl = null;
        try {
            cl = Class.forName(className);
            logger = org.apache.log4j.Logger.getLogger(cl);
        } catch (ClassNotFoundException e) {
            System.out.println("ERROR: Could not load class " + className);
        }
    }

    public void info(String cat, Object arg0) {
        if (filteredCategories.contains(cat.trim()))
            return;
        logger.info("[" + cat + "]\t " + arg0);
    }
    

    public void debug(String cat, Object arg0) {
        if (!Kernel.DEBUG)
            return;

        if (filteredCategories.contains(cat.trim()))
            return;

        StringBuilder sb = new StringBuilder();
        sb.append('[').append(cat).append("]\t ").append(arg0);
        logger.debug(sb.toString());
    }

    public void debug(String cat, String[] args) {
        if (!Kernel.DEBUG)
            return;

        if (filteredCategories.contains(cat.trim()))
            return;

        // Find calling method name and class
        Throwable t = new Throwable();
        StackTraceElement[] s = t.getStackTrace();
        String className = s[1].getClassName();
        className = className.substring(className.lastIndexOf('.')+1);
        String methodName = s[1].getMethodName();

        StringBuilder sb = new StringBuilder();
        sb.append("--> ").append(className).append('.').append(methodName);
        if (args.length > 0) {
            sb.append('{');
            for (int i = 0; i < args.length - 1; i++) {
                sb.append(args[i]);
                sb.append(", ");
            }
            sb.append(args[args.length-1]);
            sb.append('}');
        }

        sb.append(" [").append(LoggerTimer.getTimer()).append(']');

        this.debug(cat, sb.toString());
    }

    public void debug(String cat) {
        if (!Kernel.DEBUG)
            return;

        if (filteredCategories.contains(cat.trim()))
            return;

        // Find calling method name and class
        Throwable t = new Throwable();
        StackTraceElement[] s = t.getStackTrace();
        String className = s[1].getClassName();
        className = className.substring(className.lastIndexOf('.')+1);
        String methodName = s[1].getMethodName();

        StringBuilder sb = new StringBuilder();
        sb.append("--> ").append(className).append('.').append(methodName).append(" [").append(LoggerTimer.getTimer()).append("]");

        this.debug(cat, sb.toString());
    }

    public void error(String cat, Object o) {
        // Find calling method name and class
        Throwable t = new Throwable();
        StackTraceElement[] s = t.getStackTrace();
        String className = s[1].getClassName();
        className = className.substring(className.lastIndexOf('.')+1);
        String methodName = s[1].getMethodName();

        long timer = LoggerTimer.getTimer();

        StringBuilder sb = new StringBuilder();
        sb.append("[").append(cat).append("]\t ").append("--> ").append(className).append('.').append(methodName).append(" [").append(timer).append("] ").append(o);

        logger.error(sb.toString());

        if (o instanceof Exception) {
            StackTraceElement[] trace = ((Exception)o).getStackTrace();

            for (int i = 0; i < trace.length; i++) {
                error(cat, className, methodName, timer, trace[i]);
            }

        }
    }

    private void error(String cat, String className, String methodName, long timer, StackTraceElement o) {
        StringBuilder sb = new StringBuilder();
        sb.append("[").append(cat).append("] ").append("--> ").append(className).append('.').append(methodName).append(" [").append(timer).append("]\t ").append(o);

        logger.error(sb.toString());
    }

    public void internalError(Object o) {
        error(INTERNAL_ERROR, o);
    }
    
}
